﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Legend.Component.Interface;
using Microsoft.Xna.Framework.Content;
using Legend.Component.Common;
using Legend.Component.PowerBall;

namespace Legend.Object
{
    public class GameObjectManager
    {
        private static List<GameObject> gameObjectList = new List<GameObject>(30);
        private static List<GameObject> registReadyList = new List<GameObject>(30);
        private static List<GameObject> unregistReadyList = new List<GameObject>(30);
        private static BoundingFrustum viewFrustum = new BoundingFrustum(Matrix.Identity);
        private static ContentManager contentManager;
        private static Dictionary<string, int> board = new Dictionary<string,int>();
                
        public static void RegistGameObject(GameObject gameObject)
        {
            lock (registReadyList)
            {
                registReadyList.Add(gameObject);
            }
        }

        public static Dictionary<string, int> Board
        {
            get { return board; }
        }

        public static ContentManager Contents
        {
            get { return contentManager; }
            set { contentManager = value; }
        }


        public static void UnregistGameObject(GameObject gameObject)
        {
            lock (unregistReadyList)
            {
                unregistReadyList.Add(gameObject);
            }
        }

        public static BoundingFrustum ViewFrustum
        {
            get { return viewFrustum; }
        }

        public static int AddBoardValue(string name, int addValue)
        {
            if (board.ContainsKey(name))
            {
                board[name] += addValue;
            }
            else
            {
                board[name] = addValue;
            }
            return board[name];
        }

        public static int GetBoardValue(string name)
        {
            if (board.ContainsKey(name))
            {
                return board[name];
            }

            return 0;
        }

        public static void SetBoardValue(string name, int value)
        {
            board[name] = value;
        }

        public static void RemoveBoardValue(string name)
        {
            if (board.ContainsKey(name))
            {
                board.Remove(name);
            }
        }

        private static void ResolveDamaging(IDamaging damagingSrc, IDamaging damagingDst)
        {
            IDamaging.ResolveResult resultSrc = damagingDst.ResolveDamaging(damagingSrc.DamageDisposition, damagingSrc.Damage, damagingSrc.Status);
            if ((resultSrc & IDamaging.ResolveResult.Disappear) != 0)
            {
                UnregistGameObject(damagingDst.Owner);
            }
        }

        public static void Update(GameTime gameTime, ContentManager contentManager)
        {
            foreach (GameObject gameObject in unregistReadyList)
            {
                gameObjectList.Remove(gameObject);
            }
            gameObjectList.AddRange(registReadyList);
            registReadyList.Clear();
            unregistReadyList.Clear();

            // 여기서 쓰레드 처리
            List<IInputProcessor> processList = new List<IInputProcessor>();
            List<ICollision> blockList = new List<ICollision>();
            List<IDamaging> damagingList = new List<IDamaging>();

            foreach (GameObject gameObject in gameObjectList)
            {
                gameObject.Update(gameTime, contentManager);

                IMovement movement = gameObject.FindComponent<IMovement>();
                if (movement != null)
                {
                    IRenderable renderable = gameObject.FindComponent<IRenderable>();
                    Matrix transform = movement.GetTransform();

                    if (renderable != null)
                    {
                        renderable.WorldMatrix = transform;
                    }

                    ICollision collision = gameObject.FindComponent<ICollision>();
                    if (collision != null)
                    {
                        BoundingBox boundingBox = collision.LocalBoundingBox;
                        boundingBox.Min += movement.Position;
                        boundingBox.Max += movement.Position;
                        collision.BoundingBox = boundingBox;

                        if (collision.CollisionType == ICollision.CollisionTypes.Block)
                        {
                            blockList.Add(collision);
                        }

                        IDamaging damaging = gameObject.FindComponent<IDamaging>();
                        if (damaging != null)
                        {
                            damagingList.Add(damaging);
                        }
                    }
                }

                IInputProcessor processor = gameObject.FindComponent<IInputProcessor>();
                if (processor != null)
                {
                    processList.Add(processor);
                }
            }

            foreach (IInputProcessor processor in processList)
            {
                processor.ProcessInput(gameTime, blockList);
            }

            for (int i = 0; i < damagingList.Count(); ++i)
            {
                for (int j = i; j < damagingList.Count(); ++j)
                {
                    if (j == i)
                    {
                        continue;
                    }
                    IDamaging damagingDst = damagingList[j];
                    IDamaging damagingSrc = damagingList[i];

                    ICollision collisionSrc = damagingSrc.Owner.FindComponent<ICollision>();
                    ICollision collisionDst = damagingDst.Owner.FindComponent<ICollision>();
                    if (!collisionDst.BoundingBox.Intersects(collisionSrc.BoundingBox))
                    {
                        continue;
                    }

                    ResolveDamaging(damagingSrc, damagingDst);
                    ResolveDamaging(damagingDst, damagingSrc);
                }
            }
        }

        public static void Render(GraphicsDevice graphicsDevice, Matrix view, Matrix projection)
        {
            // 여기서 쓰레드 처리
            viewFrustum.Matrix = view * projection;

            foreach (GameObject gameObject in gameObjectList)
            {
                IRenderable renderable;

                renderable = gameObject.FindComponent<IRenderable>();
                if (renderable != null)
                {
                    renderable.ViewMatrix = view;
                    renderable.ProjectionMatrix = projection;
                    renderable.Render(graphicsDevice);
                }
            }
        }

        
    }
}
